package com.jzy.gulimall.ware.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzy.common.constant.OrderEnum;
import com.jzy.common.constant.WareConstant;
import com.jzy.common.exception.NoStockException;
import com.jzy.common.to.SkuHasStockRespVo;
import com.jzy.common.to.mq.OrderTo;
import com.jzy.common.to.mq.StockLockTo;
import com.jzy.common.utils.PageUtils;
import com.jzy.common.utils.Query;
import com.jzy.common.utils.R;
import com.jzy.gulimall.ware.dao.WareSkuDao;
import com.jzy.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.jzy.gulimall.ware.entity.WareOrderTaskEntity;
import com.jzy.gulimall.ware.entity.WareSkuEntity;
import com.jzy.gulimall.ware.feign.OrderFeignService;
import com.jzy.gulimall.ware.feign.ProductFeignService;
import com.jzy.gulimall.ware.service.WareOrderTaskDetailService;
import com.jzy.gulimall.ware.service.WareOrderTaskService;
import com.jzy.gulimall.ware.service.WareSkuService;
import com.jzy.gulimall.ware.vo.OrderCartItemVo;
import com.jzy.gulimall.ware.vo.OrderVo;
import com.jzy.gulimall.ware.vo.WareSkuLockVo;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;



@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Resource
    private WareSkuDao wareSkuDao;

    @Resource
    private ProductFeignService productFeignService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private WareOrderTaskService wareOrderTaskService;

    @Resource
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Resource
    private OrderFeignService orderFeignService;

    /**
     * 库存系统 商品库存 列表
     * page=1&limit=10&skuId=&wareId=
     */
    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String skuId = (String) params.get("skuId");
        if (StringUtils.isNotBlank(skuId)) {
            wrapper.eq("sku_id", skuId);
        }
        String wareId = (String) params.get("wareId");
        if (StringUtils.isNotBlank(wareId)) {
            wrapper.eq("ware_id", wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

    /**
     * 完成采购单
     * 添加库存
     */
    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        //如果还没有,则是新增记录
        List<WareSkuEntity> list = list(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if (CollectionUtil.isNotEmpty(list)) {
            wareSkuDao.addStock(skuId, wareId, skuNum);
        } else {
            WareSkuEntity skuEntity = new WareSkuEntity();
            //skuName
            skuEntity.setSkuId(skuId);
            skuEntity.setWareId(wareId);
            skuEntity.setStock(skuNum);
            skuEntity.setStockLocked(0);
            try {
                R info = productFeignService.info(skuId);
                if (info.getCode() == 0) {
                    Map skuInfo = (Map) info.get("skuInfo");
                    String skuName = (String) skuInfo.get("skuName");
                    skuEntity.setSkuName(skuName);
                } else {
                    skuEntity.setSkuName("");
                }
            } catch (Exception e) {
                skuEntity.setSkuName("");
                e.printStackTrace();
            }
            this.save(skuEntity);
        }
    }

    /**
     * 远程调用 spu管理 上架
     * 查询sku是否有库存
     */
    @Override
    public List<SkuHasStockRespVo> getSkuHasStock(List<Long> skuIds) {
        if (CollectionUtil.isNotEmpty(skuIds)) {
            return skuIds.stream().map(skuId -> {
                SkuHasStockRespVo vo = new SkuHasStockRespVo();
                Long count = baseMapper.getSkuHasStock(skuId);
                vo.setSkuId(skuId);
                vo.setHasStock(count != null && count > 0);
                return vo;
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 提交订单  生成订单
     * 远程调用  锁库存
     * 只要时运行时异常,都会回滚
     *
     * 库存解锁的场景: 1.订单过期没有支付, 被用户手动取消 2.库存锁定成功,订单回滚
     */
    @Override
    @Transactional
    public void lockStock(WareSkuLockVo wareSkuLockVo) {
        //保存库存工作单
        WareOrderTaskEntity taskEntity = new WareOrderTaskEntity();
        taskEntity.setOrderSn(wareSkuLockVo.getOrderSn());
        wareOrderTaskService.save(taskEntity);

        //按照下单的收货地址,找到一个就近仓库,锁定库存
        List<OrderCartItemVo> locks = wareSkuLockVo.getLocks();
        List<skuWareHasStock> stockList = locks.stream().map(item -> {
            skuWareHasStock stock = new skuWareHasStock();
            Long skuId = item.getSkuId();
            stock.setSkuId(skuId);
            stock.setNum(item.getCount());
            //查询商品在哪个仓库有库存
            List<Long> wareIds = baseMapper.listWareIdHasStock(skuId);
            stock.setWareId(wareIds);
            return stock;
        }).collect(Collectors.toList());
        //锁定库存
        for (skuWareHasStock stock : stockList) {
            boolean skuStock = false;
            Long skuId = stock.getSkuId();
            List<Long> wareIds = stock.getWareId();
            if (CollectionUtil.isEmpty(wareIds)) {
                //没有仓库有这个商品的库存
                throw new NoStockException(skuId);
            }
            for (Long wareId : wareIds) {
                Long count = baseMapper.lockWareStock(skuId,wareId,stock.getNum());
                if (count == 1) {
                    skuStock = true;
                    //告诉mq库存锁定成功,开启自动解锁
                    //保存库存详情工作单
                    WareOrderTaskDetailEntity detailEntity = new WareOrderTaskDetailEntity(null,skuId,"",stock.getNum(),taskEntity.getId(),wareId,WareConstant.WareLockStatusEnum.LOCK.getCode());
                    wareOrderTaskDetailService.save(detailEntity);
                    //解锁工作单
                    StockLockTo stockLockTo = new StockLockTo();
                    stockLockTo.setId(taskEntity.getId());
                    stockLockTo.setDetailId(detailEntity.getId());
                    //都锁定成功,工作单记录发给mq
                    //锁定失败,前面保存的记录回滚,不需要解锁
                    rabbitTemplate.convertAndSend(WareConstant.STOCK_EVENT_EXCHANGE, WareConstant.STOCK_CREAT_ROUTING_KEY,stockLockTo);
                    break;
                }
            }
            if (!skuStock) {
                //当前商品都没有锁住
                throw new NoStockException(skuId);
            }
        }
    }

    /**
     * 库存自动解锁 手动ack
     */
    @Override
    public void unLockStock(StockLockTo stockLockTo) {
        Long id = stockLockTo.getId();  //库存工作单的iD
        Long detailId = stockLockTo.getDetailId(); //库存工作单详情id
        WareOrderTaskDetailEntity detailEntity = wareOrderTaskDetailService.getById(detailId);
        //解锁
        //1.查询库数据关于这个订单的锁定库存信息
        //  如果: 库存锁定失败,库存回滚,无需解锁
        //  有:  库存锁定成功, 看订单情况决定解锁
        if (detailEntity != null) {
            //工作单信息 -> 订单号
            WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(id);
            String orderSn = taskEntity.getOrderSn();
            R orderStatus = orderFeignService.getOrderStatus(orderSn);
            if (orderStatus.getCode() == 0) {
                OrderVo orderVo = orderStatus.getData(new TypeReference<OrderVo>() {
                });
                if (orderVo == null || orderVo.getStatus().equals(OrderEnum.CANCLED.getCode())) {
                    //订单被取消 || 订单不存在,订单回滚
                    if (detailEntity.getLockStatus() == WareConstant.WareLockStatusEnum.LOCK.getCode()) {
                        unLockStock(detailEntity);
                    }
                }
            } else {
                throw new RuntimeException("远程调用失败");
            }
        }
    }

    /**
     * 防止卡顿
     * 订单解锁之后发送消息库存,防止库存在订单之前触发解锁
     */
    @Transactional
    @Override
    public void unLockStock(OrderTo orderTo) {
        String orderSn = orderTo.getOrderSn();
        //查一下最新的库存解锁状态,防止重复解锁库存
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getOrderTaskByOrderSn(orderSn);
        List<WareOrderTaskDetailEntity> entities = wareOrderTaskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>()
                .eq("task_id", taskEntity.getId())
                .eq("lock_status", WareConstant.WareLockStatusEnum.LOCK));
        if (CollectionUtil.isNotEmpty(entities)) {
            for (WareOrderTaskDetailEntity entity : entities) {
                unLockStock(entity);
            }
        }
    }

    /**
     * 解锁库存方法
     */
    private void unLockStock(WareOrderTaskDetailEntity detailEntity){
        System.out.println("库存解锁中....");
        //库存解锁
        baseMapper.unLockStock(detailEntity.getSkuId(),detailEntity.getWareId(),detailEntity.getSkuNum());
        //改变库存工作单状态
        detailEntity.setLockStatus(WareConstant.WareLockStatusEnum.UNLOCK.getCode());
        wareOrderTaskDetailService.updateById(detailEntity);
    }

    @Data
    private class skuWareHasStock{
        private Long skuId;

        private Integer num;

        private List<Long> wareId;
    }
}